﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Text;
using System.Windows.Forms;
using Crm.Utilities.SolutionsDeploymentTool.UI.Helpers;
using Microsoft.Xrm.Sdk;

namespace Crm.Utilities.SolutionsDeploymentTool.UI
{
    public partial class MainForm : Form
    {
        #region Attributes
        private Connection SourceConnection;
        private Connection TargetConnection;
        private SourceType SourceConnectionType
        {
            get 
            {
                if (rbDirectory.Checked)
                    return SourceType.Directory;
                
                return SourceType.CRM;
            }
            set
            {
                switch (value)
                {
                    case SourceType.CRM:
                        rbDirectory.Checked = false;
                        rbOrganization.Checked = true;
                        break;
                    case SourceType.Directory:
                        rbDirectory.Checked = true;
                        rbOrganization.Checked = false;
                        break;
                    default:
                        rbDirectory.Checked = false;
                        rbOrganization.Checked = true;
                        break;
                }
            }
        }
        #endregion

        #region CTORs
        
        public MainForm()
        {
            InitializeComponent();
            InitializeForm();
        }

        #endregion

        #region WinForm Events

        private void btConnect_Click(object sender, EventArgs e)
        {
            if (!ValidateConnectionsParameters())
                return;

            if (!ValidateSolutionsFolder(true))
            {
                MessageBox.Show("You must specify a valid solutions folder to continue.");
                return;
            }

            if (string.IsNullOrEmpty(tbTimeout.Text) || tbTimeout.Text == "0")
            {
                tbTimeout.Text = "5";
            }
            int timeout = int.Parse(tbTimeout.Text);

            if (SourceConnectionType == SourceType.CRM)
            {
                SourceConnection = new Connection(tbCrmServerUrlSource.Text,
                    tbOrgNameSource.Text,
                    tbDomainSource.Text,
                    tbUsernameSource.Text,
                    tbPasswordSource.Text,
                    GetConnectionType(true),
                    false,
                    new TimeSpan(0, timeout, 0),
                    tbExportFolder.Text,
                    SourceConnectionType,
                    cbSaveConnInfo.Checked,
                    cbSavePassword.Checked);
            }

            TargetConnection = new Connection(tbCrmServerUrlTarget.Text,
                tbOrgNameTarget.Text,
                tbDomainTarget.Text,
                tbUsernameTarget.Text,
                tbPasswordTarget.Text,
                GetConnectionType(false),
                true,
                new TimeSpan(0, timeout, 0),
                tbExportFolder.Text,
                SourceConnectionType,
                cbSaveConnInfo.Checked,
                cbSavePassword.Checked);

            lblConnectionStatus.Text = Constants.UI_CONNECTING;
            lblConnectionStatus.ForeColor = Color.Black;

            groupBoxSource.Enabled = false;
            groupBoxTarget.Enabled = false;
            groupBoxParameters.Enabled = false;

            BackgroundWorker bw = new BackgroundWorker();
            bw.DoWork += new DoWorkEventHandler(bw_TestConnections);
            bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_TestConnectionsCompleted);
            bw.RunWorkerAsync();
        }

        private void btLoadSolutions_Click(object sender, EventArgs e)
        {
            if (SourceConnectionType == SourceType.CRM)
            {
                if (!SourceConnection.IsConnected || !TargetConnection.IsConnected)
                    btConnect_Click(sender, e);

                DataCollection<Entity> CrmSolutions = CrmSolutionsHelper.GetUnmanagedSolutions(SourceConnection.GetOrganizationService());

                if (CrmSolutions.Count > 0)
                {
                    lvSolutions.Items.Clear();
                    foreach (Entity solution in CrmSolutions)
                    {
                        string solutionDisplayName = string.Format("{0} ({1})",
                                                                    solution[Constants.Solution_FriendlyName].ToString(),
                                                                    solution[Constants.Solution_Version].ToString());
                        ListViewItem item = new ListViewItem(solutionDisplayName);
                        item.Tag = solution;
                        lvSolutions.Items.Add(item);
                    }
                }
            }
            else if (SourceConnectionType == SourceType.Directory)
            {

                string[] files = Directory.GetFiles(tbExportFolder.Text);
                lvSolutions.Items.Clear();

                foreach (string file in files)
                {
                    if (Path.GetExtension(file).ToLower().EndsWith(".zip"))
                    {
                        ListViewItem item = new ListViewItem(Path.GetFileName(file).Replace(".zip", ""));
                        item.Tag = file;
                        lvSolutions.Items.Add(item);
                    }
                }
            }
        }

        private void btDisconnect_Click(object sender, EventArgs e)
        {
            btConnect.Enabled = true;
            groupBoxSource.Enabled = true;
            groupBoxTarget.Enabled = true;
            SourceConnection.IsConnected = false;
            TargetConnection.IsConnected = false;

            if (SourceConnectionType == SourceType.CRM)
            {
                gbExportSettings.Enabled = false;
            }
            gbImportSettings.Enabled = false;
            gbOperationCenter.Enabled = false;
            gbSolutions.Enabled = false;

            lvSolutions.Items.Clear();
            
            lblConnectionStatus.Text = Constants.UI_NOT_CONNECTED;
            lblConnectionStatus.ForeColor = Color.Red;
        }

        private void btMoveUp_Click(object sender, EventArgs e)
        {
            if (lvSolutions.SelectedItems.Count == 1)
            {
                int selectedIndex = lvSolutions.SelectedItems[0].Index;
                if (selectedIndex > 0)
                {
                    ListViewItem selectedItem = lvSolutions.Items[selectedIndex];
                    lvSolutions.Items.Remove(selectedItem);
                    lvSolutions.Items.Insert(selectedIndex - 1, selectedItem);
                    lvSolutions.Items[selectedIndex - 1].Selected = true;
                }
            }
            else
            {
                MessageBox.Show("Select a solution in order to move it up.");
            }
        }

        private void btMoveDown_Click(object sender, EventArgs e)
        {
            if (lvSolutions.SelectedItems.Count == 1)
            {
                int selectedIndex = lvSolutions.SelectedItems[0].Index;
                if (selectedIndex < (lvSolutions.Items.Count - 1))
                {
                    ListViewItem selectedItem = lvSolutions.Items[selectedIndex];
                    lvSolutions.Items.Remove(selectedItem);
                    lvSolutions.Items.Insert(selectedIndex + 1, selectedItem);
                    lvSolutions.Items[selectedIndex + 1].Selected = true;
                }
            }
            else
            {
                MessageBox.Show("Select a solution in order to move it down.");
            }
        }

        private void btStart_Click(object sender, EventArgs e)
        {            
            if (cbOperations.SelectedIndex == (int)OperationType.Undefined)
            {
                MessageBox.Show("Please select a valid operation to perform.");
            }
            else if ((OperationType)cbOperations.SelectedIndex == OperationType.ExportSolutions || 
                     (OperationType)cbOperations.SelectedIndex == OperationType.Export_ImportSolutions)
            {
                ExportSolutions();
            }
            else if ((OperationType)cbOperations.SelectedIndex == OperationType.ImportSolutions)
            {
                ImportSolutions();
            }
            else if ((OperationType)cbOperations.SelectedIndex == OperationType.PublishCustomizations)
            {
                PublishCustomizations(true);
            }
        }

        private void btDeleteConnections_Click(object sender, EventArgs e)
        {
            TargetConnection.ClearSavedInfo();
            SourceConnection.ClearSavedInfo();
        }

        private void rbOrganization_CheckedChanged(object sender, EventArgs e)
        {
            ToggleSourceMode();
        }

        private void btClearLogs_Click(object sender, EventArgs e)
        {
            rtbMessageCenter.Text = string.Empty;
        }

        #endregion

        #region Internal Methods 

        private void InitializeForm()
        {
            SourceConnection = new Connection(false);
            TargetConnection = new Connection(true);
 
            tbCrmServerUrlSource.Text = SourceConnection.ServerUrl;
            tbOrgNameSource.Text = SourceConnection.OrgName;
            tbUsernameSource.Text = SourceConnection.UserLogin;
            tbDomainSource.Text = SourceConnection.UserDomain;
            tbPasswordSource.Text = SourceConnection.UserPassword;
            if (SourceConnection.ConnectionMode == ConnectionType.ADFS)
                cbADFSorIFDSource.Checked = true;
            SourceConnectionType = SourceConnection.SourceConnectionType;

            tbCrmServerUrlTarget.Text = TargetConnection.ServerUrl;
            tbOrgNameTarget.Text = TargetConnection.OrgName;
            tbUsernameTarget.Text = TargetConnection.UserLogin;
            tbDomainTarget.Text = TargetConnection.UserDomain;
            tbPasswordTarget.Text = TargetConnection.UserPassword;
            if (TargetConnection.ConnectionMode == ConnectionType.ADFS)
                cbADFSorIFDTarget.Checked = true;

            tbTimeout.Text = SourceConnection.ServiceTimeout.TotalMinutes.ToString();
            tbExportFolder.Text = SourceConnection.SolutionsFolder;

            btDisconnect.Enabled = false;
            if (SourceConnectionType == SourceType.CRM)
            {
                gbExportSettings.Enabled = false;
            }
            gbImportSettings.Enabled = false;
            gbOperationCenter.Enabled = false;
            gbSolutions.Enabled = false;
            tabPage1.Focus();
        }

        private bool ValidateConnectionsParameters()
        {
            if (SourceConnectionType == SourceType.CRM)
            {
                if (String.IsNullOrEmpty(this.tbCrmServerUrlSource.Text))
                {
                    MessageBox.Show("You must enter a Source CRM Server URL.");
                    return false;
                }

                if (!Uri.IsWellFormedUriString(this.tbCrmServerUrlSource.Text, UriKind.Absolute))
                {
                    MessageBox.Show("Please specify valid source server url, e.g.: " + Environment.NewLine + Environment.NewLine +
                        "On-Premises: http://crmservername:5555" + Environment.NewLine +
                        "Hosted/IFD: https://orgname.domain.com" + Environment.NewLine +
                        "CRM Online: https://orgname.crm.dynamics.com");
                    return false;
                }

                if ((String.IsNullOrEmpty(this.tbOrgNameSource.Text) && !this.tbCrmServerUrlSource.Text.ToLowerInvariant().Contains(".dynamics.com")))
                {
                    MessageBox.Show("You must enter a source organization name.");
                    return false;
                }

                if ((this.tbCrmServerUrlSource.Text.ToLowerInvariant().Contains(".dynamics.com") && (string.IsNullOrEmpty(this.tbPasswordSource.Text) || string.IsNullOrEmpty(this.tbUsernameSource.Text))))
                {
                    MessageBox.Show("You must enter your source login and password when connecting to CRM Online");
                    return false;
                }

                try
                {
                    Uri url1 = new Uri(this.tbCrmServerUrlSource.Text);
                }
                catch
                {
                    MessageBox.Show("Invalid Source Server Url");
                    return false;
                }

                if (!tbCrmServerUrlSource.Text.StartsWith("http"))
                {
                    MessageBox.Show("Invalid Source Server Url. Url must start with http:// or https://");
                    return false;
                }
            }
            else if (SourceConnectionType == SourceType.Directory)
            {
                if (!ValidateSolutionsFolder(false))
                {
                    return false;
                }
            }

            if (String.IsNullOrEmpty(this.tbCrmServerUrlTarget.Text))
            {
                MessageBox.Show("You must enter a Target CRM Server URL.");
                return false;
            }

            if (!Uri.IsWellFormedUriString(this.tbCrmServerUrlTarget.Text, UriKind.Absolute))
            {
                MessageBox.Show("Please specify valid target server url, e.g.: " + Environment.NewLine + Environment.NewLine +
                    "On-Premises: http://crmservername:5555" + Environment.NewLine +
                    "Hosted/IFD: https://orgname.domain.com" + Environment.NewLine +
                    "CRM Online: https://orgname.crm.dynamics.com");
                return false;
            }
            if (String.IsNullOrEmpty(this.tbOrgNameTarget.Text) && !this.tbCrmServerUrlTarget.Text.ToLowerInvariant().Contains(".dynamics.com"))
            {
                MessageBox.Show("You must enter a target organization name.");
                return false;
            }

            if (this.tbCrmServerUrlTarget.Text.ToLowerInvariant().Contains(".dynamics.com") && (string.IsNullOrEmpty(this.tbPasswordTarget.Text) || string.IsNullOrEmpty(this.tbUsernameTarget.Text)))
            {
                MessageBox.Show("You must enter your target login and password when connecting to CRM Online");
                return false;
            }

            try
            {
                Uri url2 = new Uri(this.tbCrmServerUrlTarget.Text);
            }
            catch
            {
                MessageBox.Show("Invalid Server Url");
                return false;
            }

            if (!tbCrmServerUrlTarget.Text.StartsWith("http"))
            {
                MessageBox.Show("Invalid Target Server Url. Url must start with http:// or https://");
                return false;
            }

            return true;
        }

        private bool ValidateSolutionsFolder(bool promptToCreate)
        {
            if (string.IsNullOrEmpty(tbExportFolder.Text))
            {
                return false;
            }

            if (!tbExportFolder.Text.EndsWith(@"\"))
            {
                tbExportFolder.Text += @"\";
            }

            if (!Directory.Exists(tbExportFolder.Text))
            {
                if (promptToCreate)
                {
                    DialogResult res = MessageBox.Show(string.Format("The specified folder '{0}' does not exist. Do you want to create it?", tbExportFolder.Text), "Folder Not Found", MessageBoxButtons.YesNo);
                    if (res == System.Windows.Forms.DialogResult.Yes)
                    {
                        try
                        {
                            Directory.CreateDirectory(tbExportFolder.Text);
                            return true;
                        }
                        catch (Exception e)
                        {
                            MessageBox.Show("Error while creating folder : " + Environment.NewLine + e.Message);
                            return false;
                        }
                    }
                }

                MessageBox.Show(string.Format("The specified folder '{0}' does not exist.", tbExportFolder.Text), "Folder Not Found", MessageBoxButtons.OK);
                return false;
            }

            return true;
        }

        private ConnectionType GetConnectionType(bool source)
        {
            bool isADFS;
            string serverUrl;

            if (source)
            {
                isADFS = cbADFSorIFDSource.Checked;
                serverUrl = tbCrmServerUrlSource.Text;
            }
            else
            {
                isADFS = cbADFSorIFDTarget.Checked;
                serverUrl = tbCrmServerUrlTarget.Text;
            }

            if (isADFS)
                return ConnectionType.ADFS;
            if (serverUrl.Contains(".dynamics.com"))
                return ConnectionType.CrmOnline;

            return ConnectionType.Default;
        }

        private void ExportSolutions()
        {
            if (cbExportType.SelectedIndex == -1)
            {
                MessageBox.Show("You must select an export type to continue.");
                return;
            }

            // Save again to capture Export Folder in case it was missing.
            if (cbSaveConnInfo.Checked)
            {
                if (SourceConnectionType == SourceType.CRM)
                {
                    SourceConnection.SolutionsFolder = tbExportFolder.Text;
                    SourceConnection.Save(cbSavePassword.Checked);
                }

                TargetConnection.SolutionsFolder = tbExportFolder.Text;
                TargetConnection.Save(cbSavePassword.Checked);
            }

            // Disable Start Button and Operation DropDown
            btStart.Enabled = false;
            cbOperations.Enabled = false;

            if (SourceConnectionType == SourceType.CRM)
            {
                gbExportSettings.Enabled = false;
            }
            gbImportSettings.Enabled = false;
            gbSolutions.Enabled = false;

            List<Entity> solToExport = new List<Entity>(lvSolutions.CheckedItems.Count);
            for (int i = 0; i < lvSolutions.CheckedItems.Count; i++)
            {
                ListViewItem row = lvSolutions.CheckedItems[i];
                Entity solution = (Entity)row.Tag;
                solToExport.Add(solution);
            }

            if (solToExport.Count > 0)
            {
                BackgroundWorker bw = new BackgroundWorker();
                bw.WorkerReportsProgress = true;
                bw.DoWork += new DoWorkEventHandler(bw_ExportSolutions);
                bw.ProgressChanged += new ProgressChangedEventHandler(bw_ExportSolutionsProgressChanged);
                bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_ExportSolutionsCompleted);

                ExportSettings exportSettings = new ExportSettings(solToExport,
                                                                   tbExportFolder.Text,
                                                                   (ExportType)cbExportType.SelectedIndex,
                                                                   cbAutoNumbering.Checked,
                                                                   cbCalendar.Checked,
                                                                   cbCustomization.Checked,
                                                                   cbEmailTracking.Checked,
                                                                   cbGeneral.Checked,
                                                                   cbIsvConfig.Checked,
                                                                   cbMarketing.Checked,
                                                                   cbOutlookSynchronization.Checked,
                                                                   cbRelationshipRoles.Checked);

                progressBar.Maximum = solToExport.Count;
                progressBar.Value = 0;
                lblProgress.Text = string.Format("Exporting {0} Solution(s) from {1}", solToExport.Count, SourceConnection.OrgName);
                AddToMessageCenter(string.Format("Exporting {0} Solution(s) from {1}", solToExport.Count, SourceConnection.OrgName));
                
                bw.RunWorkerAsync(exportSettings);
            }
        }

        private void ImportSolutions()
        {
            if (cbPublishOptions.SelectedIndex == (int)PublishOptions.Undefined)
            {
                MessageBox.Show("You must select a publish option to continue.");
                return;
            }

            if (!ValidateSolutionsFolder(false))
            {
                MessageBox.Show("You must specify a valid Solutions folder to continue.");
                return;
            }

            if (!rbManaged.Checked && !rbUnmanaged.Checked && SourceConnectionType == SourceType.CRM)
            {
                MessageBox.Show("Please select an import type (managed or unmanaged) to continue.");
                return;
            }

            // Save again to capture Export Folder in case it was missing.
            if (cbSaveConnInfo.Checked)
            {
                SourceConnection.SolutionsFolder = tbExportFolder.Text;
                SourceConnection.Save(cbSavePassword.Checked);
                
                TargetConnection.SolutionsFolder = tbExportFolder.Text; 
                TargetConnection.Save(cbSavePassword.Checked);
            }

            // Disable Start Button and Operation DropDown
            btStart.Enabled = false;
            cbOperations.Enabled = false;

            if (SourceConnectionType == SourceType.CRM)
            {
                gbExportSettings.Enabled = false;
            }
            gbImportSettings.Enabled = false;
            gbSolutions.Enabled = false;

            List<Entity> solutionEntitiesToImport = new List<Entity>(lvSolutions.CheckedItems.Count);
            List<String> solutionFilesToImport = new List<String>(lvSolutions.CheckedItems.Count);

            for (int i = 0; i < lvSolutions.CheckedItems.Count; i++)
            {
                if (SourceConnectionType == SourceType.CRM)
                {
                    ListViewItem row = lvSolutions.CheckedItems[i];
                    Entity solution = (Entity)row.Tag;
                    solutionEntitiesToImport.Add(solution);
                }
                else
                {
                    ListViewItem row = lvSolutions.CheckedItems[i];
                    solutionFilesToImport.Add((string)row.Tag);
                }
            }

            BackgroundWorker bw = new BackgroundWorker();
            bw.WorkerReportsProgress = true;
            bw.DoWork += new DoWorkEventHandler(bw_ImportSolutions);
            bw.ProgressChanged += new ProgressChangedEventHandler(bw_ImportSolutionsProgressChanged);
            bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_ImportSolutionsCompleted);

            ImportSettings importSettings = new ImportSettings(solutionEntitiesToImport,
                                                               solutionFilesToImport,
                                                               tbExportFolder.Text,
                                                               rbManaged.Checked ? ImportType.Managed : ImportType.Unmanaged,
                                                               cbConverToManaged.Checked,
                                                               cbPublishWorkflows.Checked,
                                                               cbOverwriteUnmanagedCustomizations.Checked);

            importSettings.PublishAfterImport = cbPublishOptions.SelectedIndex == (int)PublishOptions.PublishAllAfterEachImport;
            
            progressBar.Maximum = lvSolutions.CheckedItems.Count;
            progressBar.Value = 0;
            lblProgress.Text = string.Format("Importing {0} Solution(s) to Organization {1}", lvSolutions.CheckedItems.Count, TargetConnection.OrgName);
            AddToMessageCenter(string.Format("Importing {0} Solution(s) to {1}", lvSolutions.CheckedItems.Count, TargetConnection.OrgName));

            bw.RunWorkerAsync(importSettings);
        }

        private void PublishCustomizations(bool forcePublishAll = false)
        {
            if (cbPublishOptions.SelectedIndex == (int)PublishOptions.Undefined)
            {
                MessageBox.Show("You must select a publish option to continue.");
                return;
            }

            if ((PublishOptions)cbPublishOptions.SelectedIndex == PublishOptions.PublishAllAfterAllImport || forcePublishAll)
            {
                // Disable Start Button and Operation DropDown
                btStart.Enabled = false;
                cbOperations.Enabled = false;
                if (SourceConnectionType == SourceType.CRM)
                {
                    gbExportSettings.Enabled = false;
                }
                gbImportSettings.Enabled = false;
                gbSolutions.Enabled = false;

                BackgroundWorker bw = new BackgroundWorker();
                bw.DoWork += new DoWorkEventHandler(bw_PublishCustomizations);
                bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_PublishCustomizationsCompleted);

                progressBar.Maximum = 100;
                progressBar.Value = 0;
                lblProgress.Text = string.Format("Publishing All Customizations in {0}", TargetConnection.OrgName);
                AddToMessageCenter(string.Format("Publishing All Customizations in {0}", TargetConnection.OrgName));

                bw.RunWorkerAsync();
            }
            else
            {
                // Enable Start Button and Operation DropDown
                btStart.Enabled = true;
                cbOperations.Enabled = true;
                if (SourceConnectionType == SourceType.CRM)
                {
                    gbExportSettings.Enabled = true;
                    gbImportType.Enabled = true;
                }
                gbImportSettings.Enabled = true;
                gbSolutions.Enabled = true;
            }
        }

        private void ToggleSourceMode()
        {
            if (SourceConnectionType == SourceType.CRM)
            {
                tbCrmServerUrlSource.Enabled = true;
                tbDomainSource.Enabled = true;
                tbOrgNameSource.Enabled = true;
                tbPasswordSource.Enabled = true;
                tbUsernameSource.Enabled = true;
                cbADFSorIFDSource.Enabled = true;
            }
            else if (SourceConnectionType == SourceType.Directory)
            {
                tbCrmServerUrlSource.Enabled = false;
                tbDomainSource.Enabled = false;
                tbOrgNameSource.Enabled = false;
                tbPasswordSource.Enabled = false;
                tbUsernameSource.Enabled = false;
                cbADFSorIFDSource.Enabled = false;

                gbExportSettings.Enabled = false;
            }
        }
        
        private void SetFieldsAvailability()
        {
            if (SourceConnectionType == SourceType.Directory)
            {
                cbOperations.SelectedIndex = (int)OperationType.ImportSolutions;
                cbOperations.Enabled = false;

                gbExportSettings.Enabled = false;
                rbUnmanaged.Checked = false;
                rbManaged.Checked = false;
                gbImportType.Enabled = false;
            }
        }

        private void AddToMessageCenter(string text)
        {
            rtbMessageCenter.SelectionColor = Color.Black;

            if (text.Equals(Constants.TextBox_Separator))
                rtbMessageCenter.AppendText(Environment.NewLine + Constants.TextBox_Separator);
            else if (!String.IsNullOrEmpty(rtbMessageCenter.Text))
                rtbMessageCenter.AppendText(Environment.NewLine + string.Format("{0} | {1}", DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss"), text));
            else 
                rtbMessageCenter.AppendText(string.Format("{0} | {1}", DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss"), text));
            

            rtbMessageCenter.SelectionStart = rtbMessageCenter.Text.Length;
            rtbMessageCenter.ScrollToCaret();
        }

        private void AddToMessageCenter(ExecutionMessage message)
        {
            rtbMessageCenter.SelectionColor = message.ColorCode;

            if (message.Text.Equals(Constants.TextBox_Separator))
                rtbMessageCenter.AppendText(Environment.NewLine + Constants.TextBox_Separator);
            else if (!String.IsNullOrEmpty(rtbMessageCenter.Text))
                rtbMessageCenter.AppendText(Environment.NewLine + string.Format("{0} | {1}", DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss"), message.Text));
            else
                rtbMessageCenter.AppendText(string.Format("{0} | {1}", DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss"), message.Text));
            
            rtbMessageCenter.SelectionStart = rtbMessageCenter.Text.Length;
            rtbMessageCenter.ScrollToCaret();
        }

        #endregion

        #region Background Processes

        void bw_PublishCustomizationsCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            progressBar.Value = progressBar.Maximum; 
            ExecutionMessage message = (ExecutionMessage)e.Result;
            AddToMessageCenter(message);
            lblProgress.Text = message.Text;
            AddToMessageCenter(Constants.TextBox_Separator);

            // Enable Start Button and Operation DropDown
            btStart.Enabled = true;
            cbOperations.Enabled = true;

            gbExportSettings.Enabled = true;
            gbImportSettings.Enabled = true;
            gbSolutions.Enabled = true;

            SetFieldsAvailability();
        }

        void bw_PublishCustomizations(object sender, DoWorkEventArgs e)
        {
            ExecutionMessage result = CrmSolutionsHelper.PublishAllCustomizations(TargetConnection.GetOrganizationService());
            result.Text = string.Format("Publishing All Customizations in {0} : {1}", TargetConnection.OrgName, result.Text);
            e.Result = result;
        }

        void bw_TestConnectionsCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (SourceConnectionType == SourceType.CRM && SourceConnection.IsConnected)
            {
                lblConnectionStatus.Text = Constants.UI_SOURCE_CONNECTED + (string)e.Result;
                lblConnectionStatus.ForeColor = Color.Black;
            }

            if (TargetConnection.IsConnected)
            {
                lblConnectionStatus.Text = Constants.UI_TARGET_CONNECTED + (string)e.Result;
                lblConnectionStatus.ForeColor = Color.Black;
            }

            if (!string.IsNullOrEmpty((string)e.Result))
            {
                StringBuilder sb = new StringBuilder();
                sb.Append(Constants.UI_NOT_CONNECTED);

                if (SourceConnectionType == SourceType.CRM && !SourceConnection.IsConnected)
                    sb.Append(" | " + Constants.UI_SOURCE_NOT_CONNECTED);
                if (!TargetConnection.IsConnected)
                    sb.Append(" | " + Constants.UI_TARGET_NOT_CONNECTED);
                sb.Append(" | " + (string)e.Result);

                lblConnectionStatus.Text = sb.ToString();
                lblConnectionStatus.ForeColor = Color.Red;

                groupBoxSource.Enabled = true;
                groupBoxTarget.Enabled = true;
                groupBoxParameters.Enabled = true;
                return;
            }

            if (((SourceConnectionType == SourceType.CRM && SourceConnection.IsConnected) ||
                 (SourceConnectionType == SourceType.Directory)) && TargetConnection.IsConnected)
            {
                lblConnectionStatus.Text = Constants.UI_CONNECTED;
                lblConnectionStatus.ForeColor = Color.Green;

                btConnect.Enabled = false;
                groupBoxSource.Enabled = false;
                groupBoxTarget.Enabled = false;

                btDisconnect.Enabled = true;
                gbExportSettings.Enabled = true;
                gbImportType.Enabled = true;
                gbImportSettings.Enabled = true;
                gbOperationCenter.Enabled = true;
                gbSolutions.Enabled = true;

                if (cbSaveConnInfo.Checked)
                {
                    SourceConnection.Save(cbSavePassword.Checked);
                    TargetConnection.Save(cbSavePassword.Checked);
                }

                btLoadSolutions_Click(null, null);
                tabControl1.SelectedTab = tabPage2;

                SetFieldsAvailability();
            }
            else // Cannot connect for unknown reasons
            {
                lblConnectionStatus.Text = string.Format("{0} | {1}", Constants.UI_NOT_CONNECTED, "An unknown error occured.");
                lblConnectionStatus.ForeColor = Color.Red;

                groupBoxSource.Enabled = true;
                groupBoxTarget.Enabled = true;
                groupBoxParameters.Enabled = true;
            }
        }

        void bw_TestConnections(object sender, DoWorkEventArgs e)
        {
            var result1 = string.Empty;
            var result2 = string.Empty;
            string result = string.Empty; 
            
            if (SourceConnectionType == SourceType.CRM)
            {
                result1 = SourceConnection.TestConnection();
                if (!result1.Equals(Constants.Message_Success)) result += " | Source Conn : " + result1;
            }

            result2 = TargetConnection.TestConnection();
            if (!result2.Equals(Constants.Message_Success)) result += " | Target Conn : " + result2;

            e.Result = result;
        }

        void bw_ExportSolutions(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;
            ExportSettings settings = (ExportSettings)e.Argument;

            for (int i = 0; i < settings.Solutions.Count; i++)
            {
                if ((worker.CancellationPending == true))
                {
                    e.Cancel = true;
                    break;
                }
                else
                {
                    ExecutionMessage message = new ExecutionMessage(string.Format("Exporting Solution {0} ({1}/{2})", settings.Solutions[i][Constants.Solution_FriendlyName].ToString(), (i + 1).ToString(), progressBar.Maximum));
                    worker.ReportProgress(i, message);

                    if (settings.ExportTypeSetting == ExportType.ManagedOnly || settings.ExportTypeSetting == ExportType.UnmanagedAndManaged)
                    {
                        message = CrmSolutionsHelper.ExportCrmSolution(settings.Solutions[i], settings, true, SourceConnection.GetOrganizationService());
                    }
                    if (settings.ExportTypeSetting == ExportType.UnmanagedOnly || settings.ExportTypeSetting == ExportType.UnmanagedAndManaged)
                    {
                        message = CrmSolutionsHelper.ExportCrmSolution(settings.Solutions[i], settings, false, SourceConnection.GetOrganizationService());
                    }

                    message.Text = string.Format("Exporting Solution {0} ({1}/{2}) : {3}", settings.Solutions[i][Constants.Solution_FriendlyName].ToString(), (i + 1).ToString(), progressBar.Maximum, message.Text);
                    worker.ReportProgress(i + 1, message);
                }
            }
        }

        void bw_ExportSolutionsCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            string msg = string.Format("Export Solution(s) Operation from {0} completed.", SourceConnection.OrgName);
            AddToMessageCenter(msg);
            lblProgress.Text = msg;
            progressBar.Value = progressBar.Maximum;
            AddToMessageCenter(Constants.TextBox_Separator);

            // Enable Start Button and Operation DropDown
            btStart.Enabled = true;
            cbOperations.Enabled = true;
            gbExportSettings.Enabled = true;
            gbImportSettings.Enabled = true;
            gbSolutions.Enabled = true;

            SetFieldsAvailability();
            

            if ((OperationType)cbOperations.SelectedIndex == OperationType.Export_ImportSolutions)
            {
                ImportSolutions();
            }
        }

        void bw_ExportSolutionsProgressChanged(Object sender, ProgressChangedEventArgs e)
        {
            ExecutionMessage message = (ExecutionMessage)e.UserState;
            AddToMessageCenter(message);
            lblProgress.Text = message.Text;
            progressBar.Value = e.ProgressPercentage;
        }

        void bw_ImportSolutions(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;
            ImportSettings settings = (ImportSettings)e.Argument;
            int count = 0;

            if (settings.SolutionsEntities.Count > 0)
                count = settings.SolutionsEntities.Count;
            else if (settings.SolutionFiles.Count > 0)
                count = settings.SolutionFiles.Count;
           

            for (int i = 0; i < count; i++)
            {
                if ((worker.CancellationPending == true))
                {
                    e.Cancel = true;
                    break;
                }
                else
                {
                    Guid importJobId = Guid.Empty;

                    ExecutionMessage message = null;
                    int solutionNumber = i + 1;
                    string solutionName = string.Empty;

                    if (SourceConnectionType == SourceType.CRM)
                    {
                        solutionName = settings.SolutionsEntities[i][Constants.Solution_FriendlyName].ToString();
                    
                        message = new ExecutionMessage(string.Format("Importing Solution {0} ({1}/{2})", solutionName, solutionName, progressBar.Maximum), MessageSeverity.Information);
                        worker.ReportProgress(i, message);
                        message = CrmSolutionsHelper.ImportCrmSolution(settings.SolutionsEntities[i], settings, TargetConnection.GetOrganizationService());

                        if (message.Severity == MessageSeverity.Success && settings.PublishAfterImport)
                        {
                            message = new ExecutionMessage(string.Format("Publishing Solution {0} ({1}/{2})", solutionName, solutionNumber, progressBar.Maximum), MessageSeverity.Information);
                            worker.ReportProgress(i, message);

                            message = CrmSolutionsHelper.PublishAllCustomizations(TargetConnection.GetOrganizationService());
                            message.Text = string.Format("Published Customizations after Solution [{0}] Import : {1}", solutionName, message.Text);

                            worker.ReportProgress(i, message);
                        }
                        message.Text = string.Format("Importing Solution {0} ({1}/{2}) : {3}", solutionName, solutionNumber, progressBar.Maximum, message.Text);
                    }
                    else
                    {
                        solutionName = Path.GetFileName(settings.SolutionFiles[i]);
                        message = new ExecutionMessage(string.Format("Importing Solution {0} ({1}/{2})", solutionName, solutionNumber, progressBar.Maximum), MessageSeverity.Information);
                        worker.ReportProgress(i, message);
                        message = CrmSolutionsHelper.ImportCrmSolution(settings.SolutionFiles[i], settings, TargetConnection.GetOrganizationService());

                        if (message.Severity == MessageSeverity.Success && settings.PublishAfterImport)
                        {
                            message = new ExecutionMessage(string.Format("Publishing Solution {0} ({1}/{2})", solutionName, solutionNumber, progressBar.Maximum), MessageSeverity.Information);
                            worker.ReportProgress(i, message);

                            message = CrmSolutionsHelper.PublishAllCustomizations(TargetConnection.GetOrganizationService());
                            message.Text = string.Format("Published Customizations for [{0}] : {1}", solutionName, message.Text);

                            worker.ReportProgress(i, message);
                        }

                        message.Text = string.Format("Importing Solution {0} ({1}/{2}) : {3}", solutionName, solutionNumber, progressBar.Maximum, message.Text);
                    }

                    worker.ReportProgress(i + 1, message);

                }
            }
        }

        void bw_ImportSolutionsCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            string msg = string.Format("Import Solution(s) Operation to {0} completed.", TargetConnection.OrgName);
            AddToMessageCenter(msg);
            lblProgress.Text = msg;
            progressBar.Value = progressBar.Maximum;
            AddToMessageCenter(Constants.TextBox_Separator);

            gbExportSettings.Enabled = true;
            gbImportSettings.Enabled = true;
            gbSolutions.Enabled = true;

            SetFieldsAvailability();
            PublishCustomizations();
        }

        void bw_ImportSolutionsProgressChanged(Object sender, ProgressChangedEventArgs e)
        {
            ExecutionMessage message = (ExecutionMessage)e.UserState;
            AddToMessageCenter(message);
            lblProgress.Text = message.Text;
            progressBar.Value = e.ProgressPercentage;
        }

        #endregion  
    }
}
